package main

import (
	"context"
	"crypto/ecdsa"
	"fmt"
	"log"
	"math/big"
	"os"
	"path/filepath"
	"time"

	"github.com/ethereum/go-ethereum/accounts/keystore"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/ethereum/go-ethereum/params"
)

// PrivateChainSetup 私有链设置结构
type PrivateChainSetup struct {
	client     *ethclient.Client
	privateKey *ecdsa.PrivateKey
	publicKey  *ecdsa.PublicKey
	address    common.Address
	chainID    *big.Int
}

// NewPrivateChainSetup 创建私有链设置实例
func NewPrivateChainSetup(rpcURL string) (*PrivateChainSetup, error) {
	// 连接到 Geth 节点
	client, err := ethclient.Dial(rpcURL)
	if err != nil {
		return nil, fmt.Errorf("连接到 Geth 节点失败: %v", err)
	}

	// 获取链 ID
	chainID, err := client.NetworkID(context.Background())
	if err != nil {
		return nil, fmt.Errorf("获取链 ID 失败: %v", err)
	}

	return &PrivateChainSetup{
		client:  client,
		chainID: chainID,
	}, nil
}

// GenerateAccount 生成新账户
func (pcs *PrivateChainSetup) GenerateAccount() error {
	// 生成私钥
	privateKey, err := crypto.GenerateKey()
	if err != nil {
		return fmt.Errorf("生成私钥失败: %v", err)
	}

	// 获取公钥
	publicKey := privateKey.Public()
	publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
	if !ok {
		return fmt.Errorf("获取公钥失败")
	}

	// 生成地址
	address := crypto.PubkeyToAddress(*publicKeyECDSA)

	pcs.privateKey = privateKey
	pcs.publicKey = publicKeyECDSA
	pcs.address = address

	fmt.Printf("✅ 生成新账户:\n")
	fmt.Printf("   地址: %s\n", address.Hex())
	fmt.Printf("   私钥: %x\n", crypto.FromECDSA(privateKey))

	return nil
}

// LoadAccount 从 keystore 加载账户
func (pcs *PrivateChainSetup) LoadAccount(keystorePath, password string) error {
	// 打开 keystore 目录
	ks := keystore.NewKeyStore(keystorePath, keystore.StandardScryptN, keystore.StandardScryptP)

	// 获取账户列表
	accounts := ks.Accounts()
	if len(accounts) == 0 {
		return fmt.Errorf("keystore 中没有找到账户")
	}

	// 使用第一个账户
	account := accounts[0]

	// 解锁账户
	if err := ks.Unlock(account, password); err != nil {
		return fmt.Errorf("解锁账户失败: %v", err)
	}

	pcs.address = account.Address

	fmt.Printf("✅ 加载账户: %s\n", account.Address.Hex())

	return nil
}

// CheckBalance 检查账户余额
func (pcs *PrivateChainSetup) CheckBalance() (*big.Int, error) {
	balance, err := pcs.client.BalanceAt(context.Background(), pcs.address, nil)
	if err != nil {
		return nil, fmt.Errorf("获取余额失败: %v", err)
	}

	fmt.Printf("💰 账户余额: %s ETH\n", weiToEther(balance).String())
	return balance, nil
}

// SendTransaction 发送交易
func (pcs *PrivateChainSetup) SendTransaction(to common.Address, amount *big.Int) (*types.Transaction, error) {
	// 获取 nonce
	nonce, err := pcs.client.PendingNonceAt(context.Background(), pcs.address)
	if err != nil {
		return nil, fmt.Errorf("获取 nonce 失败: %v", err)
	}

	// 获取 gas 价格
	gasPrice, err := pcs.client.SuggestGasPrice(context.Background())
	if err != nil {
		return nil, fmt.Errorf("获取 gas 价格失败: %v", err)
	}

	// 创建交易
	tx := types.NewTransaction(
		nonce,
		to,
		amount,
		params.TxGas, // 21000 gas limit for simple transfer
		gasPrice,
		nil,
	)

	// 签名交易
	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(pcs.chainID), pcs.privateKey)
	if err != nil {
		return nil, fmt.Errorf("签名交易失败: %v", err)
	}

	// 发送交易
	err = pcs.client.SendTransaction(context.Background(), signedTx)
	if err != nil {
		return nil, fmt.Errorf("发送交易失败: %v", err)
	}

	fmt.Printf("📤 交易已发送: %s\n", signedTx.Hash().Hex())
	return signedTx, nil
}

// WaitForTransaction 等待交易确认
func (pcs *PrivateChainSetup) WaitForTransaction(txHash common.Hash) (*types.Receipt, error) {
	fmt.Printf("⏳ 等待交易确认: %s\n", txHash.Hex())

	for i := 0; i < 60; i++ { // 最多等待 60 秒
		receipt, err := pcs.client.TransactionReceipt(context.Background(), txHash)
		if err == nil {
			fmt.Printf("✅ 交易已确认，区块号: %d\n", receipt.BlockNumber.Uint64())
			return receipt, nil
		}

		time.Sleep(1 * time.Second)
		if i%10 == 9 {
			fmt.Printf("   仍在等待确认... (%d/60)\n", i+1)
		}
	}

	return nil, fmt.Errorf("等待交易确认超时")
}

// GetBlockInfo 获取区块信息
func (pcs *PrivateChainSetup) GetBlockInfo(blockNumber *big.Int) error {
	block, err := pcs.client.BlockByNumber(context.Background(), blockNumber)
	if err != nil {
		return fmt.Errorf("获取区块信息失败: %v", err)
	}

	fmt.Printf("📦 区块信息:\n")
	fmt.Printf("   区块号: %d\n", block.Number().Uint64())
	fmt.Printf("   区块哈希: %s\n", block.Hash().Hex())
	fmt.Printf("   父区块哈希: %s\n", block.ParentHash().Hex())
	fmt.Printf("   时间戳: %d\n", block.Time())
	fmt.Printf("   交易数量: %d\n", len(block.Transactions()))
	fmt.Printf("   Gas 使用量: %d\n", block.GasUsed())
	fmt.Printf("   Gas 限制: %d\n", block.GasLimit())
	fmt.Printf("   矿工: %s\n", block.Coinbase().Hex())

	return nil
}

// GetNetworkInfo 获取网络信息
func (pcs *PrivateChainSetup) GetNetworkInfo() error {
	// 获取链 ID
	chainID, err := pcs.client.ChainID(context.Background())
	if err != nil {
		return fmt.Errorf("获取链 ID 失败: %v", err)
	}

	// 获取网络 ID
	networkID, err := pcs.client.NetworkID(context.Background())
	if err != nil {
		return fmt.Errorf("获取网络 ID 失败: %v", err)
	}

	// 获取最新区块号
	blockNumber, err := pcs.client.BlockNumber(context.Background())
	if err != nil {
		return fmt.Errorf("获取最新区块号失败: %v", err)
	}

	// 获取节点信息
	version, err := pcs.client.ClientVersion(context.Background())
	if err != nil {
		return fmt.Errorf("获取客户端版本失败: %v", err)
	}

	fmt.Printf("🌐 网络信息:\n")
	fmt.Printf("   客户端版本: %s\n", version)
	fmt.Printf("   链 ID: %d\n", chainID.Uint64())
	fmt.Printf("   网络 ID: %d\n", networkID.Uint64())
	fmt.Printf("   最新区块: %d\n", blockNumber)

	return nil
}

// CreateKeystore 创建 keystore 文件
func (pcs *PrivateChainSetup) CreateKeystore(keystorePath, password string) error {
	if pcs.privateKey == nil {
		return fmt.Errorf("请先生成账户")
	}

	// 确保目录存在
	if err := os.MkdirAll(keystorePath, 0755); err != nil {
		return fmt.Errorf("创建 keystore 目录失败: %v", err)
	}

	// 创建 keystore
	ks := keystore.NewKeyStore(keystorePath, keystore.StandardScryptN, keystore.StandardScryptP)

	// 导入私钥
	account, err := ks.ImportECDSA(pcs.privateKey, password)
	if err != nil {
		return fmt.Errorf("导入私钥到 keystore 失败: %v", err)
	}

	fmt.Printf("🔐 Keystore 已创建:\n")
	fmt.Printf("   路径: %s\n", keystorePath)
	fmt.Printf("   账户: %s\n", account.Address.Hex())

	return nil
}

// weiToEther 将 wei 转换为 ether
func weiToEther(wei *big.Int) *big.Float {
	ether := new(big.Float)
	ether.SetString(wei.String())
	return ether.Quo(ether, big.NewFloat(params.Ether))
}

// etherToWei 将 ether 转换为 wei
func etherToWei(ether *big.Float) *big.Int {
	wei := new(big.Float)
	wei.Mul(ether, big.NewFloat(params.Ether))
	result, _ := wei.Int(nil)
	return result
}

// DemoPrivateChain 演示私有链功能
func DemoPrivateChain() {
	fmt.Println("🚀 开始私有链演示...")

	// 连接到本地 Geth 节点
	pcs, err := NewPrivateChainSetup("http://localhost:8545")
	if err != nil {
		log.Fatalf("初始化失败: %v", err)
	}

	// 获取网络信息
	fmt.Println("\n=== 网络信息 ===")
	if err := pcs.GetNetworkInfo(); err != nil {
		log.Printf("获取网络信息失败: %v", err)
	}

	// 生成新账户
	fmt.Println("\n=== 生成账户 ===")
	if err := pcs.GenerateAccount(); err != nil {
		log.Fatalf("生成账户失败: %v", err)
	}

	// 创建 keystore
	keystorePath := filepath.Join(".", "keystore")
	fmt.Println("\n=== 创建 Keystore ===")
	if err := pcs.CreateKeystore(keystorePath, "password123"); err != nil {
		log.Printf("创建 keystore 失败: %v", err)
	}

	// 检查余额
	fmt.Println("\n=== 检查余额 ===")
	balance, err := pcs.CheckBalance()
	if err != nil {
		log.Printf("检查余额失败: %v", err)
	}

	// 如果有余额，发送交易
	if balance.Cmp(big.NewInt(0)) > 0 {
		fmt.Println("\n=== 发送交易 ===")

		// 生成接收地址
		toAddress := common.HexToAddress("0x742d35Cc6635Cb8532e5be4f5c2b4F1F8C3c8c8a")
		amount := etherToWei(big.NewFloat(0.1)) // 0.1 ETH

		tx, err := pcs.SendTransaction(toAddress, amount)
		if err != nil {
			log.Printf("发送交易失败: %v", err)
		} else {
			// 等待交易确认
			receipt, err := pcs.WaitForTransaction(tx.Hash())
			if err != nil {
				log.Printf("等待交易确认失败: %v", err)
			} else {
				fmt.Printf("✅ 交易成功，Gas 使用量: %d\n", receipt.GasUsed)
			}
		}
	}

	// 获取最新区块信息
	fmt.Println("\n=== 区块信息 ===")
	if err := pcs.GetBlockInfo(nil); err != nil {
		log.Printf("获取区块信息失败: %v", err)
	}

	fmt.Println("\n🎉 私有链演示完成！")
}

func main() {
	DemoPrivateChain()
}
